package com.itheima;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 定义一个日志切面类 LoggerAdvice
 */
@Aspect
@Component
public class LoggingAdvice {
    private Logger logger = LoggerFactory.getLogger(LoggingAdvice.class);
 @Pointcut("@annotation(com.itheima.Cache)")
 public void pointcut(){

 }
        @Before("pointcut()")
        public void before(JoinPoint joinPoint){
            System.out.println("获取目标对象的类型："+joinPoint.getTarget().getClass());
            System.out.println("获取目标对象类名："+joinPoint.getSignature().getDeclaringTypeName());
            System.out.println("获取目标对象方法名："+joinPoint.getSignature().getName());
            System.out.println("获取方法参数："+Arrays.toString(joinPoint.getArgs()));
            System.out.println("我是before通知");
        }
    /**
     * 记录方法的返回值
     * poingtcut: 关联的切入表达式
     * returning: 将方法的返回值，通过形参result进行传递
     * @AfterReturning（pointcut = "pointcut()",returning = "result")
     * 如果参数中要添加joinPoint 对象时，参数必须位于第一位。
     * Spring 在进行参数赋值时，采用index[0]下标的方式赋值
     */
    @AfterReturning(pointcut = "pointcut()",returning = "result")
    public void afterReturning(JoinPoint joinPoint,Object result){
        System.out.println(Arrays.toString(joinPoint.getArgs()));
        System.out.println("用户的返回值结果："+result);
        System.out.println("我是afterReturning通知");
    }
    /**
     * throwing = "e"动态接收程序运行时的报错信息
     * 利用异常通知进行记录
     */
    @AfterThrowing(pointcut = "pointcut()",throwing = "e")
    public void afterThrowing(Exception e){
        System.out.println("获取异常信息"+e.getMessage());
        System.out.println("获取异常的类型"+e.getClass());
        System.out.println("我是afterThrowing");
    }
    @After("pointcut()")
    public void after(){
        System.out.println("我是after通知");
    }
    /**
     * 环绕通知可以控制目标方法是否执行
     * 参数：ProceedingJoinPoint 通过Proceed方法控制目标方法执行
     * ProceedingJoinPoint 只能适用环绕通知
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint){
     Object result = null;
     try {
         System.out.println("环绕通知开始");
//         1.执行下一个通知  2.执行目标方法  3.接收返回值
         Long start = System.currentTimeMillis();
         result = joinPoint.proceed();
         Long end = System.currentTimeMillis();
         System.out.println("耗时："+(end-start));
     }catch (Throwable e){
         e.printStackTrace();
     }
     System.out.println("环绕通知结束");
     return result;
 }
}
